package com.jmb.api.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jmb.api.common.exception.LeaseException;
import com.jmb.api.common.exception.ParseException;
import com.jmb.api.common.result.ResultCodeEnum;
import com.jmb.api.core.http.ExecuteHandler;
import com.jmb.api.core.parser.Parser;
import com.jmb.api.mapper.ApiTestCaseRelyDataMapper;
import com.jmb.api.model.entity.*;
import com.jmb.api.model.entity.Module;
import com.jmb.api.model.vo.api.ApiTestCaseInfoVo;
import com.jmb.api.service.*;
import com.jmb.api.mapper.ApiTestCaseMapper;
import com.jmb.api.vo.api.ApiTestAssertVo;
import com.jmb.api.model.vo.api.cache.ApiTestCacheParameterVo;
import com.jmb.api.vo.api.ApiTestCaseVo;
import com.jmb.api.vo.api.ApiTestPreCaseVo;
import com.jmb.api.model.vo.api.rely.ApiRelyDataVO;
import com.jmb.api.vo.api.test.ApiTestCaseListTO;
import com.jmb.api.vo.api.test.ApiTestCaseListVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
* @author jinbo
* @description 针对表【api_test_case】的数据库操作Service实现
* @createDate 2025-04-08 13:53:56
*/
@Transactional
@Service
public class ApiTestCaseServiceImpl extends ServiceImpl<ApiTestCaseMapper, ApiTestCase>
    implements ApiTestCaseService {

    @Autowired
    private ApiTestCaseMapper apiTestCaseMapper;
    @Autowired
    private ApiTestAssertService apiTestAssertService;
    @Autowired
    private ApiTestCacheParameterService parameterService;
    @Autowired
    private ModuleService moduleService;
    @Autowired
    private ProjectService projectService;
    @Autowired
    private ApiTestPreCaseService apiTestPreCaseService;
    @Autowired
    private ApiTestCaseRelyDataMapper relyDataMapper;
    @Autowired
    private Parser parser;
    @Autowired
    private ExecuteHandler executeHandler;

    @Override
    public void saveApiTest(ApiTestCaseVo apiTestCase) {
        if (apiTestCase.getBodyType() >= 3 && apiTestCase.getBodyType() != 9) {
            throw new LeaseException(ResultCodeEnum.WEB_API_TEST_BODYTYPE);
        }
        // 判断用例编号是否存在
        LambdaQueryWrapper<ApiTestCase> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ApiTestCase::getCaseId, apiTestCase.getCaseId());
        Long count = apiTestCaseMapper.selectCount(queryWrapper);
        if (count > 0) {
            throw new LeaseException(ResultCodeEnum.WEB_API_TEST_CASEID);
        }
        // 判断模块是否存在
        if (moduleService.getModuleCount(apiTestCase.getModuleId()) == 0) {
            throw new LeaseException(ResultCodeEnum.WEB_API_MODULE_NOT);
        }
        // 判断项目是否存在
        if (projectService.getProjectCount(apiTestCase.getProjectId()) == 0) {
            throw new LeaseException(ResultCodeEnum.WEB_API_PROJECT_NOT);
        }

        ApiTestCase apiTest = new ApiTestCase();
        BeanUtils.copyProperties(apiTestCase, apiTest);
        this.save(apiTest);
        // 插入主数据后，获取caseId
        Integer caseId = apiTest.getCaseId();
        // 插入前置处理器
        apiTestCase.getPreCaseList().forEach(apiTestPreCaseVo -> {
            apiTestPreCaseVo.setParentCaseId(caseId);
            apiTestPreCaseService.savePreCase(apiTestPreCaseVo);
        });
        // 保存断言
        apiTestCase.getAssertList().forEach(apiTestAssertVo -> {
            apiTestAssertVo.setCaseId(caseId);
            apiTestAssertService.saveAssert(apiTestAssertVo);
        });
        // 保存后置处理器
        apiTestCase.getCacheParameterList().forEach(apiTestCacheParameterVo -> {
            apiTestCacheParameterVo.setCaseId(caseId);
            parameterService.saveCaCheParmeter(apiTestCacheParameterVo);
        });
    }

    @Override
    public void editApiTest(ApiTestCaseVo apiTestCase) {
        // 获取caseId
        Integer caseId = apiTestCase.getCaseId();
        if (apiTestCase.getBodyType() >= 3 && apiTestCase.getBodyType() != 9) {
            throw new LeaseException(ResultCodeEnum.WEB_API_TEST_BODYTYPE);
        }
        // 检查属性接口依赖是否包含自身
        this.checkApiTest(caseId, apiTestCase.getHeaders(),"headers",false);
        this.checkApiTest(caseId, apiTestCase.getParams(),"params",false);
        this.checkApiTest(caseId, apiTestCase.getFormData(),"formData",false);
        this.checkApiTest(caseId,apiTestCase.getFormDataEncoded(),"formDataEncoded",false);
        this.checkApiTest(caseId, apiTestCase.getRaw(),"raw",false);

        // 判断传入的项目编号和模块编号是否一致
        List<String> ModuleProjectList = moduleService.getModuleProjectId(apiTestCase.getModuleId(),apiTestCase.getProjectId());
        if (ModuleProjectList.isEmpty()) {
            throw new LeaseException(ResultCodeEnum.WEB_API_MODULE_PROJECT);
        }
        ApiTestCase testCase = new ApiTestCase();
        // 类型对拷
        BeanUtils.copyProperties(apiTestCase, testCase);
        // 修改用例表
        LambdaUpdateWrapper<ApiTestCase> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ApiTestCase::getCaseId, caseId);
        if (this.count(updateWrapper) ==0){
            throw new LeaseException(ResultCodeEnum.WEB_API_TEST_CASEID_NOT);
        }
        this.update(testCase, updateWrapper);

        // 编辑断言处理

        // 因为获取到的列表是不可变的集合，这边需要进行转换操作
        ArrayList<Integer> assertIds = new ArrayList<>(apiTestAssertService.selectAllAssertId(caseId));
        List<ApiTestAssertVo> assertList = apiTestCase.getAssertList();
        if (assertList !=null && !assertList.isEmpty()){
            assertList.forEach(apiTestAssertVo -> {
                // 检查断言预期结果接口的依赖是否包含自身
                this.checkApiTest(caseId,apiTestAssertVo.getExceptedResult(),"断言预期结果",false);
                apiTestAssertVo.setCaseId(caseId);
                apiTestAssertService.editAssert(apiTestAssertVo);
                // 新增没有传入caseId的数据
                if (apiTestAssertVo.getAssertId() == null){
                    apiTestAssertService.saveAssert(apiTestAssertVo);
                }else {
                    // 有就移出此次新增前的id队列
                    assertIds.removeIf(integer -> integer.equals(apiTestAssertVo.getAssertId()));
                }
            });
            assertIds.forEach(assertId -> {
                apiTestAssertService.removeById(assertId);
            });
        }else {
            LambdaQueryWrapper<ApiTestAssert> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ApiTestAssert::getCaseId,caseId);
            apiTestAssertService.remove(queryWrapper);
        }
        // 更改前置用例
        // 1. 获取所有前置用例id
        List<Integer> preCaseList = new ArrayList<>(apiTestPreCaseService.selectAllPreCaseId(caseId));
        // 2. 获取前置用例信息
        List<ApiTestPreCaseVo> preCaseVoList = apiTestCase.getPreCaseList();
        if (preCaseVoList !=null && !preCaseVoList.isEmpty()){
            preCaseVoList.forEach(apiTestPreCaseVo -> {
                Integer preCaseId = apiTestPreCaseVo.getPreCaseId();
                ApiTestCaseVo apiTestCaseVo = this.getApiTestCaseByCaseId(preCaseId);// 获取前置用例信息
                // 检查前置用例的依赖是否包含自身
                this.checkApiTest(caseId, apiTestCaseVo.getHeaders(), String.format("[%s]headers",preCaseId ), true);
                this.checkApiTest(caseId, apiTestCaseVo.getParams(), String.format("[%s]params", preCaseId), true);
                this.checkApiTest(caseId, apiTestCaseVo.getFormData(), String.format("[%s]formData", preCaseId), true);
                this.checkApiTest(caseId, apiTestCaseVo.getFormDataEncoded(), String.format("[%s]formDataEncoded", preCaseId), true);
                this.checkApiTest(caseId, apiTestCaseVo.getRaw(), String.format("[%s]raw", preCaseId), true);
                // 3. 修改已存在的前置用例
                apiTestPreCaseVo.setParentCaseId(apiTestCase.getCaseId());
                apiTestPreCaseService.editPreCase(apiTestPreCaseVo);
                // 4. 新增没有传入caseId的数据
                if (apiTestPreCaseVo.getPreCaseId() == null) {
                    apiTestPreCaseService.savePreCase(apiTestPreCaseVo);
                } else {
                    // 有就移出此次新增前的id队列
                    preCaseList.removeIf(integer -> integer.equals(apiTestPreCaseVo.getPreCaseId()));
                }
            });
            preCaseList.forEach(preCaseId -> {
                apiTestPreCaseService.removeById(preCaseId);
            });
        }else {
            // 删除用例下所有的前置用例
            LambdaQueryWrapper<ApiTestPreCase> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ApiTestPreCase::getParentCaseId,caseId);
            apiTestPreCaseService.remove(queryWrapper);
        }
        // 修改后置处理器
        List<ApiTestCacheParameterVo> cacheParameterList = apiTestCase.getCacheParameterList();
        List<Integer> parameterIds = new ArrayList<>(parameterService.selectAllCacheParameterIds(caseId));
        if (cacheParameterList!=null && !cacheParameterList.isEmpty()){
            cacheParameterList.forEach(apiTestCacheParameterVo -> {
                // 1. 修改已存在的后置处理器
                apiTestCacheParameterVo.setCaseId(apiTestCase.getCaseId());
                parameterService.editCaCheParmeter(apiTestCacheParameterVo);
                // 2. 新增没有传入caseId的数据
                if (apiTestCacheParameterVo.getProcessorId() == null){
                    parameterService.saveCaCheParmeter(apiTestCacheParameterVo);
                }else {
                    // 有就移出此次新增前的id队列
                    parameterIds.removeIf(integer -> integer.equals(apiTestCacheParameterVo.getProcessorId()));
                }
            });
            parameterIds.forEach(processorId -> {
                parameterService.removeById(processorId);
            });
        }else {
            // 删除用例下所有的后置处理器
            LambdaQueryWrapper<ApiTestCacheParameter> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ApiTestCacheParameter::getCaseId,caseId);
            parameterService.remove(queryWrapper);
        }

    }

    @Override
    public ApiTestCaseVo getApiTestCaseByCaseId(Integer caseId) {
        return apiTestCaseMapper.selectApitestCaseByCaseId(caseId);
    }

    @Override
    public IPage<ApiTestCaseListVO> getApiTestCaseList(IPage<ApiTestCaseListVO> page, ApiTestCaseListTO apiTestCaseVo) {
        return apiTestCaseMapper.selectApiTestCaseList(page, apiTestCaseVo);
    }

    @Override
    public void removeByCaseId(Integer caseId) {
        // 删除前置用例
        LambdaQueryWrapper<ApiTestPreCase> PreQueryWrapper = new LambdaQueryWrapper<>();
        PreQueryWrapper.eq(ApiTestPreCase::getParentCaseId, caseId);
        apiTestPreCaseService.remove(PreQueryWrapper);
        // 删除断言
        LambdaQueryWrapper<ApiTestAssert> AssertQueryWrapper = new LambdaQueryWrapper<>();
        AssertQueryWrapper.eq(ApiTestAssert::getCaseId, caseId);
        apiTestAssertService.remove(AssertQueryWrapper);
        // 删除后置处理器
        LambdaQueryWrapper<ApiTestCacheParameter> CacheQueryWrapper = new LambdaQueryWrapper<>();
        CacheQueryWrapper.eq(ApiTestCacheParameter::getCaseId, caseId);
        parameterService.remove(CacheQueryWrapper);
        // 删除用例
        LambdaQueryWrapper<ApiTestCase> TestCaseQueryWrapper = new LambdaQueryWrapper<>();
        TestCaseQueryWrapper.eq(ApiTestCase::getCaseId, caseId);
        this.remove(TestCaseQueryWrapper);
    }

    /**
     * 懒加载获取树型case列表
     * @param level 树层级0代表project级别、1代表module级别、2代表case级别
     * @param id level为0时，不接受该参数，默认返回全部项目列表
     *           level为1时，id为项目编号，返回该项目下所有模块
     *           level为2时，id为模块编号，返回该模块下所有用例
     * @return tree
     */
    @Override
    public JSONArray caseTree(Integer level, Integer id) {
        JSONArray result = new JSONArray();
        if (level == 0) {
            // 获取所有项目
            List<Project> projectList = projectService.list();
            projectList.forEach(project -> {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("label", project.getName());
                jsonObject.put("scope","project");
                jsonObject.put("number", project.getProjectId());
                jsonObject.put("leaf", false);
                result.add(jsonObject);});
        }else if (level == 1){
            // 获取所有模块
            List<Module> moduleList = moduleService.getAllModule(id);
            moduleList.forEach(module -> {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("label", module.getModuleName());
                jsonObject.put("scope","module");
                jsonObject.put("number", module.getModuleId());
                jsonObject.put("leaf", false);
                result.add(jsonObject);});
        }else if (level == 2){
            // 获取所有用例
            ArrayList<ApiTestCaseListVO> caseList = apiTestCaseMapper.getAllApiCaseList(id);
            caseList.forEach(apiTestCase -> {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("label", apiTestCase.getDescription());
                jsonObject.put("scope","case");
                jsonObject.put("number", apiTestCase.getCaseId());
                jsonObject.put("projectName", apiTestCase.getProjectName());
                jsonObject.put("moduleName", apiTestCase.getModuleName());
                jsonObject.put("leaf", true);
                result.add(jsonObject);});
        }
        return result;
    }

    @Override
    public Integer executeCase(ExecuteInterfaceCaseParam executeInterfaceCaseParam) throws ParseException {
        return executeHandler.executeApiTestCase(executeInterfaceCaseParam);
    }

    // 查询用例id返回详情
    @Override
    public ApiTestCaseInfoVo findInterfaceCaseByCaseId(Integer caseId) {
        return apiTestCaseMapper.selectCaseInfoByCaseId(caseId);
    }


    /**
     * 检查用例属性中是否包含自身
     *
     * @param caseId       用例编号
     * @param property     属性 headers、params、formdata、formdataencoded、raw
     * @param propertyDesc 描述
     * @param isPreCase    是否为前置用例
     */
    private void checkApiTest(Integer caseId, String property, String propertyDesc, boolean isPreCase) {
        // 提取属性
        ArrayList<String> dependencyHeaders = parser.extractDependencyName(property);
        dependencyHeaders.forEach(dependencyHeader -> {
            // 检查接口依赖是否包含自身
            ApiRelyDataVO relyDataVO = relyDataMapper.selectRelyDataByName(dependencyHeader);
            if (relyDataVO!=null){
                // 检查依赖的用例是否为自身
                Integer relyCaseId = relyDataVO.getRelyCaseId();
                if (Objects.equals(relyCaseId, caseId)){
                    if (!isPreCase){
                        throw new LeaseException(ResultCodeEnum.WEB_API_PRE_CASE);
                    }else {
                        throw new LeaseException(ResultCodeEnum.WEB_API_TEST_CASEID_NOT);
                    }
                }
            }
            // 缺少SQL依赖的接口依赖
        });

    }
}




